---
title: 'Properties'
description: '父元件與子元件的溝通橋樑'
---

屬性讓子元件與父元件可以互相溝通。
Every component has an associated properties type which describes what is passed down from the parent.
In theory, this can be any type that implements the `Properties` trait, but in practice, there is no
reason for it to be anything but a struct where each field represents a property.

## Derive macro

Instead of implementing the `Properties` trait yourself, you should use `#[derive(Properties)]` to
automatically generate the implementation instead.
Types for which you derive `Properties` must also implement `PartialEq`.

### Field attributes

When deriving `Properties`, all fields are required by default.
The following attributes allow you to give your props initial values which will be used unless they are set to another value.

:::tip
Attributes aren't visible in Rustdoc generated documentation.
The doc strings of your properties should mention whether a prop is optional and if it has a special default value.
:::

#### `#[prop_or_default]`

Initialize the prop value with the default value of the field's type using the `Default` trait.

#### `#[prop_or(value)]`

Use `value` to initialize the prop value. `value` can be any expression that returns the field's type.
For example, to default a boolean prop to `true`, use the attribute `#[prop_or(true)]`.

#### `#[prop_or_else(function)]`

Call `function` to initialize the prop value. `function` should have the signature `FnMut() -> T` where `T` is the field type.

## `PartialEq`

`Properties` require `PartialEq` to be implemented. This is so that they can be compared by Yew to call the `changed` method
only when they change.

## Memory/speed overhead of using Properties

Internally properties are reference counted. This means that only a pointer is passed down the component tree for props.
It saves us from the cost of having to clone the entire props, which might be expensive.

:::tip
Make use of `AttrValue` which is our custom type for attribute values instead of defining them as String or another similar type.
:::

## Example

```rust
use yew::Properties;
/// Importing the AttrValue from virtual_dom
use yew::virtual_dom::AttrValue;

#[derive(Clone, PartialEq)]
pub enum LinkColor {
    Blue,
    Red,
    Green,
    Black,
    Purple,
}

fn create_default_link_color() -> LinkColor {
    LinkColor::Blue
}

#[derive(Properties, PartialEq)]
pub struct LinkProps {
    /// The link must have a target.
    href: AttrValue,
    /// Also notice that we are using AttrValue instead of String
    text: AttrValue,
    /// Color of the link. Defaults to `Blue`.
    #[prop_or_else(create_default_link_color)]
    color: LinkColor,
    /// The view function will not specify a size if this is None.
    #[prop_or_default]
    size: Option<u32>,
    /// When the view function does not specify active, it defaults to true.
    #[prop_or(true)]
    active: bool,
}
```

## Props macro

The `yew::props!` macro allows you to build properties the same way the `html!` macro does it.

The macro uses the same syntax as a struct expression except that you cannot use attributes or a base expression (`Foo { ..base }`).
The type path can either point to the props directly (`path::to::Props`) or the associated properties of a component (`MyComp::Properties`).

```rust
use yew::{props, Properties, virtual_dom::AttrValue};

#[derive(Clone, PartialEq)]
pub enum LinkColor {
    Blue,
    Red,
    Green,
    Black,
    Purple,
}

fn create_default_link_color() -> LinkColor {
    LinkColor::Blue
}

#[derive(Properties, PartialEq)]
pub struct LinkProps {
    /// The link must have a target.
    href: AttrValue,
    /// Also notice that we're using AttrValue instead of String
    text: AttrValue,
    /// Color of the link. Defaults to `Blue`.
    #[prop_or_else(create_default_link_color)]
    color: LinkColor,
    /// The view function will not specify a size if this is None.
    #[prop_or_default]
    size: Option<u32>,
    /// When the view function doesn't specify active, it defaults to true.
    #[prop_or(true)]
    active: bool,
}

impl LinkProps {
    /// Notice that this function receives href and text as String
    /// We can use `AttrValue::from` to convert it to a `AttrValue`
    pub fn new_link_with_size(href: String, text: String, size: u32) -> Self {
        // highlight-start
        props! {LinkProps {
            href: AttrValue::from(href),
            text: AttrValue::from(text),
            size,
        }}
        // highlight-end
    }
}
```
